package jp.co.nes.awssupport.test.utility;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.amazonaws.services.ec2.model.ReservedInstances;
import com.amazonaws.services.elasticache.model.ReservedCacheNode;
import com.amazonaws.services.rds.model.ReservedDBInstance;
import com.amazonaws.services.redshift.model.ReservedNode;

import jp.co.nes.awssupport.common.utility.DateUtil;

/**
 * リザーブドユーティリティです。<br>
 * JUnitでAWS APIを使用せずに、リザーブドの情報を返却するのに使用します。
 */
public class JUnitReservedUtil {

    /** EC2に関するリザーブドの情報を持つデフォルトマップ */
    private static Map<String, ReservedInstances> riMapOfDefault;

    /** ElastiCacheに関するリザーブドの情報を持つデフォルトマップ */
    private static Map<String, ReservedCacheNode> rcMapOfDefault;

    /** RedShiftに関するリザーブドの情報を持つデフォルトマップ */
    private static Map<String, ReservedNode> rnMapOfDefault;

    /** RDSに関するリザーブドの情報を持つデフォルトマップ */
    private static Map<String, ReservedDBInstance> rdMapOfDefault;

    /**
     * staticイニシャライザーです。
     */
    static {
        InputStream riOfDefault = ClassLoader.getSystemResourceAsStream("ReservedInstances.csv");
        InputStream rcOfDefault = ClassLoader.getSystemResourceAsStream("ReservedCacheNode.csv");
        InputStream rdOfDefault = ClassLoader.getSystemResourceAsStream("ReservedDBInstance.csv");
        InputStream rnOfDefault = ClassLoader.getSystemResourceAsStream("ReservedNode.csv");
        riMapOfDefault = getReservedInstances(riOfDefault);
        rcMapOfDefault = getReservedCacheNode(rcOfDefault);
        rdMapOfDefault = getReservedDBInstance(rdOfDefault);
        rnMapOfDefault = getReservedNode(rnOfDefault);
    }

    /**
     * デフォルトコンストラクタです。<br>
     * 本クラスはインスタンスを生成しません。
     */
    private JUnitReservedUtil() {
    }

    /**
     * EC2に関するリザーブドの情報を持つデフォルトマップを返却します。
     *
     * @return EC2に関するリザーブドの情報を持つデフォルトマップ
     */
    public static Map<String, ReservedInstances> getReservedInstancesOfDefault() {
        return riMapOfDefault;
    }

    /**
     * EC2に関するリザーブドの情報を持つマップを返却します。<br>
     * マップの情報については、引数の入力ストリームから読み込みます。
     *
     * @param inputStream 入力ストリーム
     * @return EC2に関するリザーブドの情報を持つマップ
     */
    public static Map<String, ReservedInstances> getReservedInstances(InputStream inputStream) {
        Map<String, ReservedInstances> resultMap = new HashMap<>();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"))) {
            boolean isHeader = true;
            while (true) {
                String line = reader.readLine();
                if (line == null) {
                    break;
                }

                if (isHeader) {
                    isHeader = false;
                    continue;
                }

                String[] values = line.split(",");

                for (int i = 0; i < values.length; i++) {
                    // 両端から " を削除
                    values[i] = values[i].substring(1, values[i].length() - 1);

                    // nullという文字列の場合、nullに変換
                    if ("null".equals(values[i])) {
                        values[i] = null;
                    }
                }

                ReservedInstances ri = new ReservedInstances();
                ri.setReservedInstancesId(values[0]);
                ri.setInstanceType(values[1]);
                ri.setStart(DateUtil.toDate(values[2]));
                ri.setEnd(DateUtil.toDate(values[3]));
                ri.setDuration(new Long(values[4]));
                if (!StringUtils.isEmpty(values[5])) {
                    ri.setInstanceCount(new Integer(values[5]));
                }
                ri.setProductDescription(values[6]);
                ri.setOfferingType(values[8]);
                ri.setOfferingClass(values[9]);
                ri.setFixedPrice(new Float(values[11]));
                resultMap.put(values[0], ri);
            }
            return resultMap;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * ElastiCacheに関するリザーブドの情報を持つデフォルトマップを返却します。<br>
     * 現状は、常に空のマップが返却されます。
     *
     * @return ElastiCacheに関するリザーブドの情報を持つデフォルトマップ
     */
    public static Map<String, ReservedCacheNode> getReservedCacheNodeOfDefault() {
        return rcMapOfDefault;
    }

    /**
     * ElastiCacheに関するリザーブドの情報を持つマップを返却します。<br>
     * 現状は、常に空のマップが返却されます。
     *
     * @param inputStream 入力ストリーム
     * @return ElastiCacheに関するリザーブドの情報を持つマップ
     */
    public static Map<String, ReservedCacheNode> getReservedCacheNode(InputStream inputStream) {
        return new HashMap<>();
    }

    /**
     * RedShiftに関するリザーブドの情報を持つデフォルトマップを返却します。<br>
     * 現状は、常に空のマップが返却されます。
     *
     * @return RedShiftに関するリザーブドの情報を持つデフォルトマップ
     */
    public static Map<String, ReservedNode> getReservedNodeOfDefault() {
        return rnMapOfDefault;
    }

    /**
     * RedShiftに関するリザーブドの情報を持つマップを返却します。<br>
     * 現状は、常に空のマップが返却されます。
     *
     * @param inputStream 入力ストリーム
     * @return RedShiftに関するリザーブドの情報を持つマップ
     */
    public static Map<String, ReservedNode> getReservedNode(InputStream inputStream) {
        return new HashMap<>();
    }

    /**
     * RDSに関するリザーブドの情報を持つデフォルトマップを返却します。
     *
     * @return RDSに関するリザーブドの情報を持つデフォルトマップ
     */
    public static Map<String, ReservedDBInstance> getReservedDBInstanceOfDefault() {
        return rdMapOfDefault;
    }

    /**
     * RDSに関するリザーブドの情報を持つマップを返却します。<br>
     * マップの情報については、引数の入力ストリームから読み込みます。
     *
     * @param inputStream 入力ストリーム
     * @return RDSに関するリザーブドの情報を持つマップ
     */
    public static Map<String, ReservedDBInstance> getReservedDBInstance(InputStream inputStream) {
        Map<String, ReservedDBInstance> resultMap = new HashMap<>();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"))) {
            boolean isHeader = true;
            while (true) {
                String line = reader.readLine();
                if (line == null) {
                    break;
                }

                if (isHeader) {
                    isHeader = false;
                    continue;
                }

                String[] values = line.split(",");

                for (int i = 0; i < values.length; i++) {
                    // 両端から " を削除
                    values[i] = values[i].substring(1, values[i].length() - 1);

                    // nullという文字列の場合、nullに変換
                    if ("null".equals(values[i])) {
                        values[i] = null;
                    }
                }

                ReservedDBInstance rd = new ReservedDBInstance();
                rd.setReservedDBInstanceId(values[0]);
                rd.setDBInstanceClass(values[1]);
                rd.setStartTime(DateUtil.toDate(values[2]));
                //rd.setEnd(DateUtil.toDate(values[3]));
                rd.setDuration(new Integer(values[4]));
                if (!StringUtils.isEmpty(values[5])) {
                    rd.setDBInstanceCount(new Integer(values[5]));
                }
                rd.setProductDescription(values[6]);
                rd.setOfferingType(values[8]);
                //rd.setOfferingClass(values[9]);
                if (!StringUtils.isEmpty(values[10])) {
                    Boolean multiAZ = Boolean.FALSE;
                    if (values[10].equals("1")) {
                        multiAZ = Boolean.TRUE;
                    }
                    rd.setMultiAZ(multiAZ);
                }
                rd.setFixedPrice(new Double(values[11]));
                resultMap.put(values[0], rd);
            }
            return resultMap;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
